package com.honey.generator.java;

import java.util.List;
import java.util.Set;

import org.java.plugin.PluginLifecycleException;

import com.honey.compilation.java.AbstractJavaCompilation;
import com.honey.compilation.java.Block;
import com.honey.compilation.java.Field;
import com.honey.compilation.java.InnerClass;
import com.honey.compilation.java.InnerEnum;
import com.honey.compilation.java.Method;
import com.honey.compilation.java.StaticBlock;
import com.honey.configureation.Context;
import com.honey.core.CorePlugin;
import com.honey.core.compiler.CompilationException;
import com.honey.core.types.FullyQualifiedJavaType;
import com.honey.core.utils.EmptyUtility;
import com.honey.core.utils.ObjectFactory;
import com.honey.core.utils.ReflectUtility;
import com.honey.core.utils.StringUtility;
import com.honey.generator.java.extension.point.AddFieldListener;
import com.honey.generator.java.extension.point.AddInnerClassListener;
import com.honey.generator.java.extension.point.AddInnerEnumListener;
import com.honey.generator.java.extension.point.AddMethodListener;
import com.honey.generator.java.extension.point.AddStaticBlockListener;
import com.honey.generator.java.extension.point.BeginClassListener;
import com.honey.generator.java.extension.point.BeginFieldListener;
import com.honey.generator.java.extension.point.BeginFileCommentListener;
import com.honey.generator.java.extension.point.BeginImportListener;
import com.honey.generator.java.extension.point.BeginInnerClassListener;
import com.honey.generator.java.extension.point.BeginInnerEnumListener;
import com.honey.generator.java.extension.point.BeginMethodListener;
import com.honey.generator.java.extension.point.BeginStaticBlockListener;
import com.honey.generator.java.extension.point.GeneratorJavaClass;

/**
 * 编译java文件
 * @author Administrator
 *
 */
abstract class AbstractCompilation  implements Compilation{
	
	private AbstractJavaCompilation abstractJavaCompilation = null;
	
	private GeneratorJavaClassPlugin belongPlugin = null;
	
	public AbstractCompilation(AbstractJavaCompilation abstractJavaCompilation){
		this.abstractJavaCompilation =  abstractJavaCompilation;
	}
	
	/* (non-Javadoc)
	 * @see com.honey.generator.java.Compilation#doCompilation()
	 */
	@Override
	public AbstractJavaCompilation doCompilation(GeneratorJavaClass generatorJavaClass) {
		AbstractJavaCompilation answer =  null;
		try {
			Context context =((CorePlugin)ObjectFactory.getRequestPlugin(belongPlugin, "honey.core.plugin")).getContextInstant();
			String rootpackage = context.getProjectEnvironmentHolder().getRootPackage();
			
			FullyQualifiedJavaType type = this.abstractJavaCompilation.getType();
			String packageName = type.getPackageName();
			//判定当前类的包名是在根包名的范围内,如果不是加入根包名称
			if(StringUtility.stringHasValue(rootpackage) && !packageName.startsWith(rootpackage)){
				String newPackageName =rootpackage + packageName;
				if( packageName.length() == 0 ){
					newPackageName = newPackageName.substring( 0 , newPackageName.length() - 1 );
				}
				type.setPackageName(newPackageName);
			}
			//复制新的编译对象
			answer = this.cloneAbstractJavaCompilation(abstractJavaCompilation);
			append(abstractJavaCompilation, answer,generatorJavaClass);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return answer;
	}

	/**
	 * 
	 * @param source 源
	 * @param target 目标
	 */
	private void append(AbstractJavaCompilation source , AbstractJavaCompilation target, GeneratorJavaClass generatorJavaClass){
		//file comment
		List<String> fileComments = source.getFileComments();
		doBeginFileCommentListener(target);
		target.addFileComment(fileComments);
		
		//import
		Set<FullyQualifiedJavaType>  importedTypes = source.getImportedTypes() ;
		doBeginImportListener(target);
		target.addImportedType(importedTypes);
		
		Set<String> staticImports = source.getStaticImports() ;
		target.addStaticImports(staticImports);
		
		FullyQualifiedJavaType[] importClasses = generatorJavaClass.importImportClass();
		if(  importClasses != null){
			target.addImportedType(importClasses); 
		}

		// java comment
		List<String>  classComments = source.getClassComments() ;
		doBeginClassListener(target);
		target.addClassComment(classComments);
		
		//field
		List<Field> fields = source.getFields();
		doBeginFieldListener(target);
		for(Field field : fields){
			field = doAddFieldListener(field);
			if(field != null)target.addField(field);
		}
		Field arrayField[] = generatorJavaClass.importFields();
		if(arrayField != null ){
			for(Field field : arrayField){
				field = doAddFieldListener(field);
				if(field != null)target.addField(field);
			}
		}
		
		//static block
		List<Block> staticBlocks = source.getStaticBlocks();
		doBeginStaticBlockListener(target);
		for(Block block : staticBlocks){
			block = doAddStaticBlockListener((StaticBlock)block);
			if(block != null)target.addStaticBlocks(block);
		}
		StaticBlock arrayBlocks[] = generatorJavaClass.importStaticBlocks();
		if(arrayBlocks != null ){
			for(Block block: arrayBlocks){
				block = doAddStaticBlockListener((StaticBlock)block);
				if(block != null)target.addStaticBlocks(block);
			}
		}
		
		//method
		Set<Method> methods = source.getMethods();
		doBeginMethodListener(target);
		for(Method method : methods){
			method = doAddMethodListener(method);
			if(method != null)target.addMethod(method);
		}
		Method []arrayMethods = generatorJavaClass.importMethods();
		if( arrayMethods != null){
			for(Method method : arrayMethods){
				method = doAddMethodListener(method);
				if(method != null)target.addMethod(method);
			}
		}
		
		//inner Enum
		List<InnerEnum> innerEnums = source.getInnerEnums();
		doBeginInnerEnumListener(target);
		for(InnerEnum innerEnum : innerEnums){
			innerEnum = doAddInnerEnumListener(innerEnum);
			if( innerEnum != null) target.addInnerEnum(innerEnum);
		} 
		InnerEnum[] innerEnumClasses = generatorJavaClass.importInnerEnumClass();
		if( innerEnumClasses!= null ){
			for(InnerEnum innerEnum : innerEnumClasses){
				innerEnum = doAddInnerEnumListener(innerEnum);
				if( innerEnum != null) target.addInnerEnum(innerEnum);
			} 
		}
		
		// inner class
		List<InnerClass> list = source.getInnerClasses();
		doBeginInnerCLassListener(target);
		for(InnerClass innerClass : list ){
			innerClass =  doAddInnerClassListener(innerClass);
			if( innerClass != null )target.addInnerClass(innerClass); 
		}
		InnerClass[] innerClasses = generatorJavaClass.importInnerClass();
		if( innerClasses != null){
			for(InnerClass innerClass : innerClasses ){
				innerClass =  doAddInnerClassListener(innerClass);
				if( innerClass != null )target.addInnerClass(innerClass); 
			}
		}
	}
	
	/**
	 * 执行添加属性事件监听
	 * @param field 属性
	 * @return
	 */
	private Field doAddFieldListener(Field field){
		Field answer = field ;
		try {
			AddFieldListener<Field>[] addFieldListenerChain =  belongPlugin.getAddFieldListener();
			if( !EmptyUtility.isObjectArrayEmpty(addFieldListenerChain) ){
				for(AddFieldListener<Field> listener : addFieldListenerChain ){
					if(answer != null ) answer = listener.doListener(answer) ;
					else break ;
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
		return answer;
	}
	
	/**
	 * 执行添加方法事件监听 
	 * @param method 方法
	 * @return
	 */
	private Method doAddMethodListener(Method method){
		Method answer = method ;
		try {
			AddMethodListener<Method>[] addMethodListenerChain =  belongPlugin.getAddMethodListener();
			if( !EmptyUtility.isObjectArrayEmpty(addMethodListenerChain) ){
				for(AddMethodListener<Method> listener : addMethodListenerChain ){
					if(answer != null ) answer = listener.doListener(answer) ;
					else break ;
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
		return answer;
	}
	
	/**
	 * 执行添加静态块事件监听
	 * @param staticBlock 静态块
	 * @return
	 */
	private StaticBlock doAddStaticBlockListener(StaticBlock staticBlock){
		StaticBlock answer = staticBlock ;
		try {
			AddStaticBlockListener<StaticBlock>[] addStaticBlockListenerChain =  belongPlugin.getAddStaticBlockListener();
			if( !EmptyUtility.isObjectArrayEmpty(addStaticBlockListenerChain) ){
				for(AddStaticBlockListener<StaticBlock> listener : addStaticBlockListenerChain ){
					if(answer != null ) answer = listener.doListener(answer) ;
					else break ;
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
		return answer;
	}
	
	/**
	 * 执行添加内部类事件监听
	 * @param innerClass 内部类
	 * @return
	 */
	private InnerClass doAddInnerClassListener(InnerClass innerClass){
		InnerClass answer = innerClass ;
		try {
			AddInnerClassListener<InnerClass>[] addInnerClassListenerChain =  belongPlugin.getAddInnerClassListener();
			if( !EmptyUtility.isObjectArrayEmpty(addInnerClassListenerChain) ){
				for(AddInnerClassListener<InnerClass> listener : addInnerClassListenerChain ){
					if(answer != null ) answer = listener.doListener(answer) ;
					else break ;
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
		return answer;
	}
	
	/**
	 * 执行添加内部类事件监听
	 * @param innerEnum 内部枚举
	 * @return
	 */
	private InnerEnum doAddInnerEnumListener(InnerEnum innerEnum){
		InnerEnum answer = innerEnum ;
		try {
			AddInnerEnumListener<InnerEnum>[] addInnerEnumListenerChain =  belongPlugin.getAddInnerEnumListener();
			if( !EmptyUtility.isObjectArrayEmpty(addInnerEnumListenerChain) ){
				for(AddInnerEnumListener<InnerEnum> listener : addInnerEnumListenerChain ){
					if(answer != null ) answer = listener.doListener(answer) ;
					else break ;
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
		return answer;
	}
	
	/**
	 * 执行开始添加类注释事件监听
	 * @param abstractJavaCompilation 
	 * @return
	 */
	private void doBeginClassListener(AbstractJavaCompilation abstractJavaCompilation){
		try {
			BeginClassListener[] beginClassListenerChain =  belongPlugin.getBeginClassListener();
			if( !EmptyUtility.isObjectArrayEmpty(beginClassListenerChain) ){
				for(BeginClassListener listener : beginClassListenerChain ){
					listener.doListener(abstractJavaCompilation);
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
	}

	
	/**
	 * 执行开始添加属性事件监听
	 * @param abstractJavaCompilation
	 * @return
	 */
	private void doBeginFieldListener(AbstractJavaCompilation abstractJavaCompilation){
		try {
			BeginFieldListener[] beginFieldListenerChain =  belongPlugin.getBeginFieldListener();
			if( !EmptyUtility.isObjectArrayEmpty(beginFieldListenerChain) ){
				for(BeginFieldListener listener : beginFieldListenerChain ){
					listener.doListener(abstractJavaCompilation);
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 执行开始添加java文件注释事件监听
	 * @param abstractJavaCompilation
	 * @return
	 */
	private void doBeginFileCommentListener(AbstractJavaCompilation abstractJavaCompilation){
		try {
			BeginFileCommentListener[] beginFileCommentListenerChain =  belongPlugin.getBeginFileCommentListener();
			if( !EmptyUtility.isObjectArrayEmpty(beginFileCommentListenerChain) ){
				for(BeginFileCommentListener listener : beginFileCommentListenerChain ){
					listener.doListener(abstractJavaCompilation);
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 执行开始导入包事件监听
	 * @param abstractJavaCompilation
	 * @return
	 */
	private void doBeginImportListener(AbstractJavaCompilation abstractJavaCompilation){
		try {
			BeginImportListener[] beginImportListenerChain =  belongPlugin.getBeginImportListener();
			if( !EmptyUtility.isObjectArrayEmpty(beginImportListenerChain) ){
				for(BeginImportListener listener : beginImportListenerChain ){
					listener.doListener(abstractJavaCompilation);
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 执行开始内部类事件监听
	 * @param abstractJavaCompilation
	 * @return
	 */
	private void doBeginInnerCLassListener(AbstractJavaCompilation abstractJavaCompilation){
		try {
			BeginInnerClassListener[] beginInnerClassListenerChain =  belongPlugin.getBeginInnerClassListener();
			if( !EmptyUtility.isObjectArrayEmpty(beginInnerClassListenerChain) ){
				for(BeginInnerClassListener listener : beginInnerClassListenerChain ){
					listener.doListener(abstractJavaCompilation);
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
	}
	  
	/**
	 * 执行开始枚举事件监听
	 * @param abstractJavaCompilation
	 * @return
	 */
	private void doBeginInnerEnumListener(AbstractJavaCompilation abstractJavaCompilation){
		try {
			BeginInnerEnumListener[] beginInnerEnumListenerChain =  belongPlugin.getBeginInnerEnumListener();
			if( !EmptyUtility.isObjectArrayEmpty(beginInnerEnumListenerChain) ){
				for(BeginInnerEnumListener listener : beginInnerEnumListenerChain ){
					listener.doListener(abstractJavaCompilation);
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 执行开始方法区域事件监听
	 * @param abstractJavaCompilation
	 * @return
	 */
	private void doBeginMethodListener(AbstractJavaCompilation abstractJavaCompilation){
		try {
			BeginMethodListener[] beginMethodListenerChain =  belongPlugin.getBeginMethodListener();
			if( !EmptyUtility.isObjectArrayEmpty(beginMethodListenerChain) ){
				for(BeginMethodListener listener : beginMethodListenerChain ){
					listener.doListener(abstractJavaCompilation);
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 执行开始静态块事件监听
	 * @param abstractJavaCompilation
	 * @return
	 */
	private void doBeginStaticBlockListener(AbstractJavaCompilation abstractJavaCompilation){
		try {
			BeginStaticBlockListener[] beginStaticBlockListenerChain =  belongPlugin.getBeginStaticBlockListener();
			if( !EmptyUtility.isObjectArrayEmpty(beginStaticBlockListenerChain) ){
				for(BeginStaticBlockListener listener : beginStaticBlockListenerChain ){
					listener.doListener(abstractJavaCompilation);
				}
			}
		} catch (PluginLifecycleException e) {
			e.printStackTrace();
		}
	}

	/**
	 * @return the abstractJavaCompilation
	 */
	public final AbstractJavaCompilation getAbstractJavaCompilation() {
		return abstractJavaCompilation;
	}

	/**
	 * @return the belongPlugin
	 */
	final GeneratorJavaClassPlugin getBelongPlugin() {
		return belongPlugin;
	}

	/**
	 * @param belongPlugin the belongPlugin to set
	 */
	final void setBelongPlugin(GeneratorJavaClassPlugin belongPlugin) {
		this.belongPlugin = belongPlugin;
	}
	
	abstract AbstractJavaCompilation cloneAbstractJavaCompilation(AbstractJavaCompilation abstractJavaCompilation)  throws CompilationException;
	
	private static final String[] CLONE_FIELD=new String[]{
		"annotations",
		"importedTypes",
		"staticImports",
		"superInterfaceTypes",
		"superClass",
		"generic",
		"autoAddGetterMethod",
		"autoAddSetterMethod",
		"enumFields",
	};
	
	void cloneFiled( AbstractJavaCompilation from ,AbstractJavaCompilation to  ) throws CompilationException{
		Object tmp  = null;
		for(String fieldName : CLONE_FIELD){
			tmp = ReflectUtility.getFieldValue(from, fieldName);
			ReflectUtility.setValueToField(to, fieldName, tmp);
		}
	}
}
